﻿using System;
using System.Collections.Generic;
using System.Text;
using Eqwww.Domain.Models.SystemManage;
using System.Linq;
using Eqwww.Data;
using System.Security.Claims;
using Eqwww.Code;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using Eqwww.App.Identity;

namespace Eqwww.App.Authorize
{
    public class AuthorizeApp
    {
        private UserApp _userApp;
        private RoleApp _roleApp;
        private ApplicationDbContext _context;

        public AuthorizeApp(UserApp userApp, RoleApp roleApp, ApplicationDbContext context)
        {
            _userApp = userApp;
            _roleApp = roleApp;
            _context = context;
        }

        /// <summary>
        /// 获取指定用户的菜单列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public IEnumerable<ModuleModel> GetAuthorizedMenus(ClaimsPrincipal principal)
        {
            //获取用户
            var user = _userApp.GetUserAsync(principal).Result;
            if (user == null)
                return null;
            if (user.DeleteMark == true||user.IsDisabled==true)
            {
                return null;
            }
            //获取用户所在所有角色
            var roleNames = _userApp.GetRolesAsync(user).Result;
            var roleIds = from p in _roleApp.Roles.Where(x => x.DeleteMark != true && roleNames.Contains(x.Name)) select p.Id;
            //获取角色所有策略
            var strategoryIds = from p in _context.Sys_StrategoryRoles.Where(x => roleIds.Contains(x.RoleId)) select p.StrategoryId;
            var strategorys = _context.Sys_Strategorys.Where(x => x.DeleteMark != true && strategoryIds.Contains(x.Id));
            //如果策略中存在超管策略，返回全部菜单
            if (strategorys.Any(x => x.IsSuper == true))
            {
                return _context.Sys_Modules.Where(x => x.DeleteMark != true && x.MenuMark == true).OrderBy(x => x.SortCode).ToList();
            }
            //否则返回查询结果
            else
            {
                var trueStrategoryIds = from p in strategorys select p.Id;
                var modules = from p in _context.Sys_StrategoryModules
                              join q in _context.Sys_Modules
                              on p.ModuleId equals q.Id
                              where trueStrategoryIds.Contains(p.StrategoryId) && q.DeleteMark != true && q.MenuMark == true
                              select q;

                return modules.Distinct().OrderBy(x => x.SortCode).ToList();
            }


        }

        public IEnumerable<ModuleButtonModel> GetAuthorizedModuleButtons(ClaimsPrincipal principal, string moduleCode, ModuleButtonPosition position)
        {
            //获取用户
            var user = _userApp.GetUserAsync(principal).Result;
            if (user == null)
                return null;
            if (user.DeleteMark == true || user.IsDisabled == true)
            {
                return null;
            }

            var module = _context.Sys_Modules.FirstOrDefault(x => x.DeleteMark != true && x.Code.ToLower() == moduleCode.ToLower());
            if (module == null)
                return null;

            //获取用户所在所有角色
            var roleNames = _userApp.GetRolesAsync(user).Result;
            var roleIds = from p in _roleApp.Roles.Where(x => x.DeleteMark != true && roleNames.Contains(x.Name)) select p.Id;
            //获取角色所有策略
            var strategoryIds = from p in _context.Sys_StrategoryRoles.Where(x => roleIds.Contains(x.RoleId)) select p.StrategoryId;
            var strategorys = _context.Sys_Strategorys.Where(x => x.DeleteMark != true && strategoryIds.Contains(x.Id));
            //如果策略中存在超管策略，返回全部按钮
            if (strategorys.Any(x => x.IsSuper == true))
            {
                return _context.Sys_ModuleButtons.Where(x => x.ModuleId == module.Id && x.DeleteMark != true && x.ParentId == null&&x.ModuleButtonPosition==position).OrderBy(x => x.SortCode).ToList();
            }
            else
            {
                var trueStrategoryIds = from p in strategorys select p.Id;
                var result = (from p in _context.Sys_StrategoryModuleButtons
                                          join q in _context.Sys_ModuleButtons
                                          on p.ModuleButtonId equals q.Id
                                          where trueStrategoryIds.Contains(p.StrategoryId) && q.ModuleId == module.Id && q.DeleteMark != true && q.ParentId == null && q.ModuleButtonPosition == position
                                          select q).ToList();

                return result.OrderBy(x=>x.SortCode).ToList();
            }
        }

        public IEnumerable<ModuleButtonModel> GetAuthorizedModuleButtonsByParentCode(ClaimsPrincipal principal, string parentCode, ModuleButtonPosition position)
        {
            //获取用户
            var user = _userApp.GetUserAsync(principal).Result;
            if (user == null)
                return null;
            if (user.DeleteMark == true || user.IsDisabled == true)
            {
                return null;
            }

            var parent = _context.Sys_ModuleButtons.FirstOrDefault(x => x.Code == parentCode && x.DeleteMark != true);
            if (parent == null)
                return null;

            //获取用户所在所有角色
            var roleNames = _userApp.GetRolesAsync(user).Result;
            var roleIds = from p in _roleApp.Roles.Where(x => x.DeleteMark != true && roleNames.Contains(x.Name)) select p.Id;
            //获取角色所有策略
            var strategoryIds = from p in _context.Sys_StrategoryRoles.Where(x => roleIds.Contains(x.RoleId)) select p.StrategoryId;
            var strategorys = _context.Sys_Strategorys.Where(x => x.DeleteMark != true && strategoryIds.Contains(x.Id));
            //如果策略中存在超管策略，返回全部按钮
            if (strategorys.Any(x => x.IsSuper == true))
            {
                return _context.Sys_ModuleButtons.Where(x => x.ParentId == parent.Id && x.DeleteMark != true  && x.ModuleButtonPosition == position).OrderBy(x => x.SortCode).ToList();
            }
            else
            {
                var trueStrategoryIds = from p in strategorys select p.Id;
                var result = from p in _context.Sys_StrategoryModuleButtons
                             join q in _context.Sys_ModuleButtons
                             on p.ModuleButtonId equals q.Id
                             where trueStrategoryIds.Contains(p.StrategoryId) && q.ParentId == parent.Id && q.DeleteMark != true && q.ModuleButtonPosition == position
                             select q;
                return result.OrderBy(x=>x.SortCode).ToList();
            }
        }

        /// <summary>
        /// 获取所有模块和按钮的树形菜单开关列表
        /// </summary>
        /// <returns></returns>
        public List<TreeCollapseToggleModel> GetModuleAndButtonTreeCollapseToggleList()
        {
            var data = new List<TreeCollapseToggleModel>();

            var modules = from p in _context.Sys_Modules.AsNoTracking().Where(x => x.DeleteMark != true)
                          select new TreeCollapseToggleModel
                          {
                              Id = p.Id,
                              Text = p.Name,
                              Url = p.Url,
                              ParentId = p.ParentId,
                              SortCode = p.SortCode,
                              Icon="list"
                          };

            var buttons = from p in _context.Sys_ModuleButtons.AsNoTracking().Where(x => x.DeleteMark != true)
                          select new TreeCollapseToggleModel
                          {
                              Id = p.Id,
                              Text = p.Name,
                              Url = p.Url,
                              ParentId = string.IsNullOrEmpty(p.ParentId)?p.ModuleId:p.ParentId,
                              SortCode = p.SortCode,
                              Icon="touch_app"
                          };

            var moduleClaims = from p in _context.Sys_ModuleClaims.AsNoTracking().Where(x => x.DeleteMark != true)
                               select new TreeCollapseToggleModel
                               {
                                   Id = p.Id,
                                   Text = p.Name,
                                   Url = p.Description,
                                   ParentId = p.ModuleId,
                                   SortCode = p.SortCode,
                                   Icon= "lightbulb_outline"
                               };

            var buttonClaims = from p in _context.Sys_ModuleButtonClaims.AsNoTracking().Where(x => x.DeleteMark != true)
                               select new TreeCollapseToggleModel
                               {
                                   Id = p.Id,
                                   Text = p.Name,
                                   Url = p.Description,
                                   ParentId = p.ButtonId,
                                   SortCode = p.SortCode,
                                   Icon= "lightbulb_outline"
                               };

            data.AddRange(modules);
            data.AddRange(buttons);
            data.AddRange(moduleClaims);
            data.AddRange(buttonClaims);

            return data;
        }

        /// <summary>
        /// 根据策略id获取所有模块和按钮的树形菜单开关列表
        /// </summary>
        /// <param name="strategoryId"></param>
        /// <returns></returns>
        public List<TreeCollapseToggleModel> GetAuthorizedModuleAndButtonTreeCollapseToggleListByStrategoryId(string strategoryId)
        {
            var data = GetModuleAndButtonTreeCollapseToggleList();
            var authorizedModuleIds = from p in _context.Sys_StrategoryModules.AsNoTracking().Where(x => x.StrategoryId == strategoryId)
                                      select p.ModuleId;
            var authorizedButtonIds = from p in _context.Sys_StrategoryModuleButtons.AsNoTracking().Where(x => x.StrategoryId == strategoryId)
                                      select p.ModuleButtonId;
            var authorizedModuleClaimIds = from p in _context.Sys_StrategoryModuleClaims.AsNoTracking().Where(x => x.StrategoryId == strategoryId)
                                           select p.ClaimId;
            var authorizedButtonClaimIds = from p in _context.Sys_StrategoryModuleButtonClaims.AsNoTracking().Where(x => x.StrategoryId == strategoryId)
                                           select p.ClaimId;

            foreach(var item in data)
            {
                item.CanToggle = true;
                if (authorizedModuleIds.Contains(item.Id) || authorizedButtonIds.Contains(item.Id) || authorizedModuleClaimIds.Contains(item.Id) || authorizedButtonClaimIds.Contains(item.Id))
                    item.ToggleMark = true;
                item.Expend = true;
                item.Disabled = false;
            }
            return data;
        }


        public async Task<bool> AuthorizeUrlAsync(string moduleId, ClaimsPrincipal principal, string url)
        {
            if (string.IsNullOrEmpty(moduleId))
                return false;

            if (!principal.Identity.IsAuthenticated)
                return false;

            //获取用户
            var user =await _userApp.GetUserAsync(principal);
            if (user == null)
                return false;

            //用户如果被禁用,则直接返回false
            if(user.IsDisabled==true)
                return false;

            //获取用户所属角色列表
            var roles =await _userApp.GetRolesAsync(user);
            var roleIds = from p in _roleApp.Roles.Where(x => roles.Contains(x.Name) && x.DeleteMark != true) select p.Id;

            //获取角色所有策略列表
            var strategoryIds = from p in _context.IQueryable<StrategoryRoleModel>().Where(x => roleIds.Contains(x.RoleId)) select p.StrategoryId;
            var strategorys = _context.IQueryable<StrategoryModel>().Where(x => x.DeleteMark != true && strategoryIds.Contains(x.Id));

            //如果有超管策略，返回成功
            if (strategorys.Any(x => x.IsSuper == true))
                return true;

            //否则，获取模块信息
            var trueStrategoryIds = from p in strategorys select p.Id;

            var modules = from p in _context.Sys_StrategoryModules
                          join q in _context.Sys_Modules
                          on p.ModuleId equals q.Id
                          where trueStrategoryIds.Contains(p.StrategoryId) && q.DeleteMark != true &&q.Url.ToLower()==url.ToLower() &&q.Id==moduleId
                          select q;

            //模块验证成功
            if (modules.Any())
                return true;

            //否则，获取按钮信息
            var buttons = from p in _context.Sys_StrategoryModuleButtons
                          join q in _context.Sys_ModuleButtons
                          on p.ModuleButtonId equals q.Id
                          where trueStrategoryIds.Contains(p.StrategoryId) && q.DeleteMark != true && q.Url.ToLower() == url.ToLower()&&q.ModuleId==moduleId
                          select q;

            //按钮验证成功
            if (buttons.Any())
                return true;

            //返回未授权
            return false;
        }
    }
}
